D:\a\vk-layer-for-rust\vk-layer-for-rust\vulkan-layer-macros\src\lib.rs
Line | Count | Source |
1 | | // Copyright 2023 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #![warn(missing_docs)] |
16 | | |
17 | | //! Macros for `vulkan-layer`. |
18 | | |
19 | | use proc_macro::TokenStream; |
20 | | use proc_macro2::TokenStream as TokenStream2; |
21 | | use quote::quote; |
22 | | use syn::{parse_macro_input, ItemImpl, Type}; |
23 | | |
24 | | mod details; |
25 | | mod dummy; |
26 | | |
27 | | /// Derive the implementation of the `vulkan_layer::GlobalHooksInfo` trait from the implementation |
28 | | /// of the `vulkan_layer::GlobalHooks` trait. |
29 | | /// |
30 | | /// This attribute macro should be used over an implementation item of the |
31 | | /// `vulkan_layer::GlobalHooks` trait, and will implement the `vulkan_layer::GlobalHooksInfo` trait |
32 | | /// for the type: |
33 | | /// * `GlobalHooksInfo::hooked_commands` returns a list of the overridden methods that appear in the |
34 | | /// implementation item. |
35 | | /// * `GlobalHooksInfo::HooksType` and `GlobalHooksInfo::HooksRefType` are defined as `Self` and |
36 | | /// `&Self`. |
37 | | /// * `GlobalHooksInfo::hooks` returns `self`. |
38 | | /// |
39 | | /// # Examples |
40 | | /// |
41 | | /// ``` |
42 | | /// use ash::vk; |
43 | | /// use vulkan_layer::{ |
44 | | /// auto_globalhooksinfo_impl, GlobalHooks, GlobalHooksInfo, LayerResult, LayerVulkanCommand, |
45 | | /// VkLayerInstanceLink, |
46 | | /// }; |
47 | | /// |
48 | | /// #[derive(Default)] |
49 | | /// struct MyGlobalHooks; |
50 | | /// |
51 | | /// #[auto_globalhooksinfo_impl] |
52 | | /// impl GlobalHooks for MyGlobalHooks { |
53 | | /// fn create_instance( |
54 | | /// &self, |
55 | | /// _p_create_info: &vk::InstanceCreateInfo, |
56 | | /// _layer_instance_link: &VkLayerInstanceLink, |
57 | | /// _p_allocator: Option<&vk::AllocationCallbacks>, |
58 | | /// _p_instance: *mut vk::Instance, |
59 | | /// ) -> LayerResult<ash::prelude::VkResult<()>> { |
60 | | /// LayerResult::Unhandled |
61 | | /// } |
62 | | /// } |
63 | | /// |
64 | | /// let my_global_hooks: MyGlobalHooks = Default::default(); |
65 | | /// assert!(std::ptr::eq(&my_global_hooks, my_global_hooks.hooks())); |
66 | | /// assert_eq!( |
67 | | /// MyGlobalHooks::hooked_commands(), |
68 | | /// [LayerVulkanCommand::CreateInstance] |
69 | | /// ); |
70 | | /// ``` |
71 | | #[proc_macro_attribute] |
72 | 3 | pub fn auto_globalhooksinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream { |
73 | 3 | let original_item: TokenStream2 = item.clone().into(); |
74 | 3 | let input = parse_macro_input!(item as ItemImpl); |
75 | 3 | let target_trait = quote!(::vulkan_layer::GlobalHooksInfo); |
76 | 3 | let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| { |
77 | 0 | let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait); |
78 | 0 | let compile_error = e.to_compile_error(); |
79 | 0 | quote! { |
80 | 0 | #dummy |
81 | 0 | #compile_error |
82 | 0 | } |
83 | 3 | }); |
84 | 3 | quote! { |
85 | 3 | #original_item |
86 | 3 | #to_append |
87 | 3 | } |
88 | 3 | .into() |
89 | 3 | } |
90 | | |
91 | | /// Derive the implementation of the `vulkan_layer::InstanceInfo` trait from the implementation of |
92 | | /// the `vulkan_layer::InstanceHooks`. |
93 | | /// |
94 | | /// This attribute macro should be used over an implementation item of the |
95 | | /// `vulkan_layer::InstanceHooks` trait, and will implement the `vulkan_layer::InstanceInfo` trait |
96 | | /// for the type: |
97 | | /// * `InstanceInfo::hooked_commands` returns a list of the overridden methods that appear in the |
98 | | /// implementation item. |
99 | | /// * `InstanceInfo::HooksType` and `InstanceInfo::HooksRefType` are defined as `Self` and `&Self`. |
100 | | /// * `InstanceInfo::hooks` returns `self`. |
101 | | /// |
102 | | /// # Examples |
103 | | /// |
104 | | /// ``` |
105 | | /// use ash::vk; |
106 | | /// use std::mem::MaybeUninit; |
107 | | /// use vulkan_layer::{ |
108 | | /// auto_instanceinfo_impl, InstanceHooks, InstanceInfo, LayerResult, LayerVulkanCommand, |
109 | | /// }; |
110 | | /// |
111 | | /// #[derive(Default)] |
112 | | /// struct MyInstanceHooks; |
113 | | /// |
114 | | /// #[auto_instanceinfo_impl] |
115 | | /// impl InstanceHooks for MyInstanceHooks { |
116 | | /// fn get_physical_device_features( |
117 | | /// &self, |
118 | | /// _physical_device: vk::PhysicalDevice, |
119 | | /// _p_features: &mut MaybeUninit<vk::PhysicalDeviceFeatures>, |
120 | | /// ) -> LayerResult<()> { |
121 | | /// LayerResult::Unhandled |
122 | | /// } |
123 | | /// } |
124 | | /// |
125 | | /// let my_instance_hooks: MyInstanceHooks = Default::default(); |
126 | | /// assert!(std::ptr::eq(my_instance_hooks.hooks(), &my_instance_hooks)); |
127 | | /// assert_eq!( |
128 | | /// MyInstanceHooks::hooked_commands(), |
129 | | /// [LayerVulkanCommand::GetPhysicalDeviceFeatures] |
130 | | /// ); |
131 | | /// ``` |
132 | | #[proc_macro_attribute] |
133 | 3 | pub fn auto_instanceinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream { |
134 | 3 | let original_item: TokenStream2 = item.clone().into(); |
135 | 3 | let input = parse_macro_input!(item as ItemImpl); |
136 | 3 | let target_trait = quote!(::vulkan_layer::InstanceInfo); |
137 | 3 | let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| { |
138 | 0 | let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait); |
139 | 0 | let compile_error = e.to_compile_error(); |
140 | 0 | quote! { |
141 | 0 | #dummy |
142 | 0 | #compile_error |
143 | 0 | } |
144 | 3 | }); |
145 | 3 | quote! { |
146 | 3 | #original_item |
147 | 3 | #to_append |
148 | 3 | } |
149 | 3 | .into() |
150 | 3 | } |
151 | | |
152 | | /// Derive the implementation of the `vulkan_layer::DeviceInfo` trait from the implementation of the |
153 | | /// `vulkan_layer::DeviceHooks` trait. |
154 | | /// |
155 | | /// This attribute macro should be used over an implementation item of the |
156 | | /// `vulkan_layer::DeviceHooks` trait, and will implement the `vulkan_layer::DeviceInfo` trait for |
157 | | /// the type: |
158 | | /// * `DeviceInfo::hooked_commands` returns a list of the overridden methods that appear in the |
159 | | /// implementation item. |
160 | | /// * `DeviceInfo::HooksType` and `DeviceInfo::HooksRefType` are defined as `Self` and `&Self`. |
161 | | /// * `DeviceInfo::hooks` returns `self`. |
162 | | /// |
163 | | /// # Examples |
164 | | /// |
165 | | /// ``` |
166 | | /// use ash::vk; |
167 | | /// use vulkan_layer::{ |
168 | | /// auto_deviceinfo_impl, DeviceHooks, DeviceInfo, LayerResult, LayerVulkanCommand, |
169 | | /// }; |
170 | | /// |
171 | | /// #[derive(Default)] |
172 | | /// struct MyDeviceHooks; |
173 | | /// |
174 | | /// #[auto_deviceinfo_impl] |
175 | | /// impl DeviceHooks for MyDeviceHooks { |
176 | | /// fn create_image( |
177 | | /// &self, |
178 | | /// _p_create_info: &vk::ImageCreateInfo, |
179 | | /// _p_allocator: Option<&vk::AllocationCallbacks>, |
180 | | /// ) -> LayerResult<ash::prelude::VkResult<vk::Image>> { |
181 | | /// LayerResult::Unhandled |
182 | | /// } |
183 | | /// } |
184 | | /// |
185 | | /// let my_device_hooks: MyDeviceHooks = Default::default(); |
186 | | /// assert!(std::ptr::eq(my_device_hooks.hooks(), &my_device_hooks)); |
187 | | /// assert_eq!( |
188 | | /// MyDeviceHooks::hooked_commands(), |
189 | | /// [LayerVulkanCommand::CreateImage] |
190 | | /// ); |
191 | | /// ``` |
192 | | #[proc_macro_attribute] |
193 | 3 | pub fn auto_deviceinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream { |
194 | 3 | let original_item: TokenStream2 = item.clone().into(); |
195 | 3 | let input = parse_macro_input!(item as ItemImpl); |
196 | 3 | let target_trait = quote!(::vulkan_layer::DeviceInfo); |
197 | 3 | let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| { |
198 | 0 | let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait); |
199 | 0 | let compile_error = e.to_compile_error(); |
200 | 0 | quote! { |
201 | 0 | #dummy |
202 | 0 | #compile_error |
203 | 0 | } |
204 | 3 | }); |
205 | 3 | quote! { |
206 | 3 | #original_item |
207 | 3 | #to_append |
208 | 3 | } |
209 | 3 | .into() |
210 | 3 | } |
211 | | |
212 | | /// Declare the required introspection queries for Android given an instantiated |
213 | | /// `vulkan_layer::Global` type. |
214 | | /// |
215 | | /// All functions are defined without name mangling, so that they are exported as C symbols in the |
216 | | /// generated dynamic library. This is recommended by |
217 | | /// [the Vulkan loader doc](https://github.com/KhronosGroup/Vulkan-Loader/blob/280997da523951c4016f4ca6af66d58a31e36ab3/docs/LoaderLayerInterface.md#layer-manifest-file-usage:~:text=These%20introspection%20functions%20are%20not%20used%20by%20the%20Khronos%20loader%20but%20should%20be%20present%20in%20layers%20to%20maintain%20consistency.%20The%20specific%20%22introspection%22%20functions%20are%20called%20out%20in%20the%20Layer%20Manifest%20File%20Format%20table): |
218 | | /// |
219 | | /// > These introspection functions are not used by the Khronos loader but should be present in |
220 | | /// > layers to maintain consistency. The specific "introspection" functions are called out in the |
221 | | /// > Layer Manifest File Format table. |
222 | | /// |
223 | | /// According to the |
224 | | /// [the Vulkan loader doc](https://github.com/KhronosGroup/Vulkan-Loader/blob/280997da523951c4016f4ca6af66d58a31e36ab3/docs/LoaderLayerInterface.md#layer-manifest-file-format), introspection queries include: |
225 | | /// * `vkEnumerateInstanceLayerProperties` |
226 | | /// * `vkEnumerateInstanceExtensionProperties` |
227 | | /// * `vkEnumerateDeviceLayerProperties` |
228 | | /// * `vkEnumerateDeviceExtensionProperties` |
229 | | /// * `vkGetInstanceProcAddr` |
230 | | /// * `vkGetDeviceProcAddr` |
231 | | /// # Examples |
232 | | /// |
233 | | /// ``` |
234 | | /// # use std::sync::Arc; |
235 | | /// # use vulkan_layer::{StubGlobalHooks, StubInstanceInfo, StubDeviceInfo, Layer, Global, declare_introspection_queries, LayerManifest}; |
236 | | /// # use once_cell::sync::Lazy; |
237 | | /// # use ash::{vk, self}; |
238 | | /// # |
239 | | /// #[derive(Default)] |
240 | | /// struct MyLayer(StubGlobalHooks); |
241 | | /// |
242 | | /// impl Layer for MyLayer { |
243 | | /// // ... |
244 | | /// # type GlobalHooksInfo = StubGlobalHooks; |
245 | | /// # type InstanceInfo = StubInstanceInfo; |
246 | | /// # type DeviceInfo = StubDeviceInfo; |
247 | | /// # type InstanceInfoContainer = StubInstanceInfo; |
248 | | /// # type DeviceInfoContainer = StubDeviceInfo; |
249 | | /// # |
250 | | /// # fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static { |
251 | | /// # static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default); |
252 | | /// # &*GLOBAL |
253 | | /// # } |
254 | | /// # |
255 | | /// # fn manifest() -> LayerManifest { |
256 | | /// # Default::default() |
257 | | /// # } |
258 | | /// # |
259 | | /// # fn global_hooks_info(&self) -> &Self::GlobalHooksInfo { |
260 | | /// # &self.0 |
261 | | /// # } |
262 | | /// # |
263 | | /// # fn create_instance_info( |
264 | | /// # &self, |
265 | | /// # _: &vk::InstanceCreateInfo, |
266 | | /// # _: Option<&vk::AllocationCallbacks>, |
267 | | /// # _: Arc<ash::Instance>, |
268 | | /// # _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr, |
269 | | /// # ) -> Self::InstanceInfoContainer { |
270 | | /// # Default::default() |
271 | | /// # } |
272 | | /// # |
273 | | /// # fn create_device_info( |
274 | | /// # &self, |
275 | | /// # _: vk::PhysicalDevice, |
276 | | /// # _: &vk::DeviceCreateInfo, |
277 | | /// # _: Option<&vk::AllocationCallbacks>, |
278 | | /// # _: Arc<ash::Device>, |
279 | | /// # _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr, |
280 | | /// # ) -> Self::DeviceInfoContainer { |
281 | | /// # Default::default() |
282 | | /// # } |
283 | | /// } |
284 | | /// |
285 | | /// type MyGlobal = Global::<MyLayer>; |
286 | | /// declare_introspection_queries!(MyGlobal); |
287 | | /// # let _: vk::PFN_vkEnumerateInstanceLayerProperties = vkEnumerateInstanceLayerProperties; |
288 | | /// # let _: vk::PFN_vkEnumerateInstanceExtensionProperties = vkEnumerateInstanceExtensionProperties; |
289 | | /// # let _: vk::PFN_vkEnumerateDeviceLayerProperties = vkEnumerateDeviceLayerProperties; |
290 | | /// # let _: vk::PFN_vkEnumerateDeviceExtensionProperties = vkEnumerateDeviceExtensionProperties; |
291 | | /// # let _: vk::PFN_vkGetInstanceProcAddr = vkGetInstanceProcAddr; |
292 | | /// # let _: vk::PFN_vkGetDeviceProcAddr = vkGetDeviceProcAddr; |
293 | | /// ``` |
294 | | #[proc_macro] |
295 | 1 | pub fn declare_introspection_queries(item: TokenStream) -> TokenStream { |
296 | 1 | let global_type = parse_macro_input!(item as Type); |
297 | 1 | details::declare_introspection_queries_impl(&global_type) |
298 | 1 | .unwrap_or_else(|e| e.to_compile_error()0 ) |
299 | 1 | .into() |
300 | 1 | } |